iT邦幫忙

2023 iThome 鐵人賽

DAY 26
0
Mobile Development

30 天輕鬆學會 Flutter 測試系列 第 26

Day 26 我該怎麼測試?

  • 分享至 

  • xImage
  •  

前兩天談論了測試的 Why 與 What,今天我們就來談談測試的 How 了,首先就讓我們來討論測試案例的議題吧。

設計測試案例

在寫測試的時候,如果測試目標的行為很簡單,裡頭只有一個 if 判斷,我們很容易就能列出兩個測試案例,if 成立的狀況與 if 不成立的狀況。

Future<void> purhcase(Product product) async {
	var wallet = _walletRepository.get();
	if (product.price > wallet.money) {
		throw MoneyNotEnough();
	}

	_productRepository.purchase(product);
}

在上面的例子中,我們很容易的可以列出兩種情境。

  1. 餘額不足
  2. 餘額足夠

當然我們甚至還會測試取得餘額失敗與購買失敗的非正流程。

大多時候,我們從客戶那邊了解的是需求的規則,到了開發階段,我們直接拍腦袋思考正常路徑有哪些情況,非正常路徑有哪些情況,轉成一個一個的測試案例,那每次我們拆解測試案例都這麼簡單嗎?

稍微複雜一點的邏輯

假設我們正在設計一個計算遊樂園票價的計算機,票種可以分成全票 100 元、半票 50 元,購買時如果身份是軍警可以打 8 折,如果是學生則可以 7 折。由於規則比較複雜,所以測試案例也隨著越來越多,那我們要怎麼知道測試案例否準備的足夠完整呢?會不會還有重要的情境沒考慮到?其實我們是可以依靠一些分析測試案例的方法來解決問題。

列出所有組合

分析測試案例最簡單的方式,就是就是把所有可能的變因組合都列出來,以上面的例子來說,我們就可列出 2 * 3 = 6 種組合。

票種 職業
1 全票 軍警
2 全票 學生
3 全票 其他職業
4 半票 軍警
5 半票 學生
6 半票 其他職業

但其實聰明的觀眾很快就會發現,一旦變因多的時候,例如身分證字號有符合 3 碼的人免費。此時,可以發現測試案例也會跟著暴增,此時我們可以考慮使用其他的測試方式。

Pairwise Testing

在 Pairwise Testing 中,不要求列出所有組合,而是讓兩兩一組的變因組合至少出現在某個測試案例中。例如:軍警 x 全票就是一種組合。

職業 職業 是否身分證字號符合 3 碼
1 軍警 全票 Yes
2 軍警 半票 No
3 學生 全票 Yes
4 學生 半票 No
5 其他職業 全票 Yes
6 其他職業 半票 No
7 其他職業 半票 Yes

可以發現,使用 Pairwise Testing 方法,讓原本需要 2 * 3 * 2 = 12 個測試案例可以減少到 7 個,當變因更多時,能更有效地減少案例。那好奇的觀眾朋友可能會問,這樣會不會錯誤就發生在其他組合呢?答案是有可能會,所以在使用 Pairwise Testing 時,我們還是得檢查一下設計組合,增加明顯有意義的組合,或去除掉一些可能沒有意義的組合,例如軍警 x 半票的組合。

不過 Pairwise Testing 看似好像美好,但實際上還是有一些限制,如果變因不是離散的,就很難使用這種方式,假設買門票可以使用折價券,折數在 1 折 ~ 9 折之間,可能有 88 折,可能有 55 折,顯然我們不太可能真的窮舉可能的折數。

Boundary-Value Analysis

當我們測試變因跟數字有關時,我們就可以使用這個邊界值分析方法,在選擇合法與不合法邊界的值來測試,可能會比較容易找到有沒處理到的情境。以上面的例子來說 0.9 折 、1 折、1.1 折、8.9 折、9 折、9.1 折 …等等,可能就是適合的測試選項。

0.png

出處:https://en.wikipedia.org/wiki/Boundary-value_analysis

不同的測試方法也可以混合著使用,例如我們就可以用邊界值分析法找出幾個有用的值,再來做 Pairwise Testing。

更多的測試案例分析方法

其實我們只舉了一些簡單常見的方法,每個方法都有他的限制與適用情境,並沒有一個方法可以用在各種情況,所以如果想更好的分析測試案例,我們還需要認識許多其他的分析測試案例方法,例如:Decision Table、Equivalence partitioning、State Transition Testing …等,這些方法除了可以拿來分析測試案例,也可以拿來在開發之前,分析需求的各種情境,有興趣的朋友也可以參考 David Ko 的學習之旅

兩種不同的測試策略

當我們設計好測試案例之後,接下來就是寫測試的時間了。關於怎麼寫測試,我們在前面的文章講了很多,這邊我們補充兩種不同的測試策略:社交性測試與孤島型測試。

孤島型測試

寫單元測試時,我們會用測試替身取代 SUT 以外的所有依賴,並設定假資料給測試替身,使得 SUT 可以走不同流程,這個稱為孤島型測試

1.jpg

出處:https://martinfowler.com/bliki/UnitTest.html

但是我們也可以想想,最初我們使用測試替身的目的是為了取代難以控制的依賴,來讓測試穩定快速,若今天我們使用真的依賴放進 SUT 中也不會造成問題,那我們是否還需要測試替身?

社交型測試

社交型測試的策略中,我們僅僅會在難以測試的時候,才使用測試替身協作。其他時候都是讓 SUT 與真正的類別互動。當然,在這種策略之下,雖然我們依賴是使用正式程式碼在用的類別,但是我們測試的主角還是 SUT 本身,而不是依賴。

2.jpg

出處:https://martinfowler.com/bliki/UnitTest.html

兩種測試有什麼差別?

在孤島型測試中,測試除了知道 SUT 和 SUT 有哪些依賴之外,測試也對於 SUT 怎麼用測試替身是有一定了解的,因為我們要在測試中對測試替身設定一些假資料。但是在社交型測試中,測試只會知道 SUT 與 SUT 有哪些依賴,測試不會認識 SUT 怎麼與測試替身互動。那測試知不知道 SUT 與依賴如何互動有什麼差別呢?其中一個差別會發生在重構的時候,使用孤島型測試時,如果我們修改了 SUT 與依賴的互動方式,測試也需要跟著修改。相反的,社交型測試則有比較大的機會不用修改。

這兩種測試策略其實也沒有誰好誰壞,因為我們的最終目的都是測試可以快又穩定,有時候我們會發現使用真依賴的社交型測試比較方便,也時候我們會發現寫孤島型的測試比較方便,需要開發人員根據不同的情況選擇。

小結

雖然我們介紹了二十幾天的測試技巧,但其實與測試相關的議題並不只這些,隨著我們測試越寫越多,我們開始會碰觸到各種不同的議題,寫測試與寫程式一樣,都有許多十分值得深入討論的議題,需要持續不斷的學習與思考,才能讓提高寫測試的效率。


上一篇
Day 25 我該測試什麼?
下一篇
Day 27 測試足夠了嗎?
系列文
30 天輕鬆學會 Flutter 測試30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言